package com.xunk.equipment.service.zhijia.service;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xunk.common.core.constant.HttpStatus;
import com.xunk.common.core.domain.EquipmentResponse;
import com.xunk.equipment.domain.EquipmentDO;
import com.xunk.equipment.mapper.EquipmentMapper;
import com.xunk.equipment.mapper.HomeMapper;
import com.xunk.equipment.service.BaseService;
import com.xunk.equipment.service.IAirConditionerService;
import com.xunk.equipment.vo.response.uhome.UhomeAirConditionerResponse;
import com.xunk.equipment.websocket.WebsocketManager;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.CompletableFuture;

/**
 * @ProjectName: HIM
 * @Package: com.xunk.equipment.service.zhijia.service
 * @ClassName: UhomeAirConditionerService
 * @Author: luanzhiwei
 * @Description: 智家空调service
 * @Date: 2021/6/16 9:47
 * @Version: 1.0
 */
@Service(value = "uplus-air-conditioner")
@Slf4j
public class UhomeAirConditionerService implements IAirConditionerService {


    @Autowired
    private ZhijiaService zhijiaService;
    @Autowired
    private EquipmentMapper equipmentMapper;
    @Autowired
    private BaseService baseService;

    @Autowired
    private HomeMapper homeMapper;


    /**
     * 获取设备当前状态值信息
     *
     * @param equipmentDO 当前设备信息，包含设备id，设备厂商
     * @return
     */
    @Override
    public EquipmentResponse getEquipmentInfo(EquipmentDO equipmentDO) {
        String deviceSn = equipmentDO.getDeviceSn();
        final Long homeId = equipmentMapper.selectHomeIdByDeviceSn(deviceSn);
        Map<String, Object> cacheMap = zhijiaService.getShadowByDeviceSn(homeId, equipmentDO.getDeptId(), deviceSn);
        UhomeAirConditionerResponse response = new UhomeAirConditionerResponse();
        response.setDeviceName(equipmentDO.getDeviceName());
        response.setDeviceType(equipmentDO.getDeviceType());
        response.setDeviceSn(deviceSn);

        // 智家空调 info：①室外温度 ②室内温度 ③室内PM2.5 ④室内湿度 ⑤空气质量等级
        //reported 包含全部设备属性
        final Map reported = (Map) cacheMap.get("reported");
        final Boolean onOffStatus = Convert.toBool(reported.get("onOffStatus"));
        response.setOn(onOffStatus);
        final List<Map<String, Object>> module = (List<Map<String, Object>>) cacheMap.get("module");
        final Map moduleInfo = module.get(0);
        final Map info = (Map) moduleInfo.get("moduleInfos");
        final Optional<Map<String, Object>> first = module.stream().filter(item -> ObjectUtil.equals(item.get("moduleType"), "basemodule")).findFirst();
        if (first.isPresent()) {
            final Map<String, Object> firstMap = first.get();
            final Map firstInfo = (Map) firstMap.get("moduleInfos");
            response.setModel(Convert.toStr(firstInfo.get("hardwareType")));
        }
        response.setFirmWare(Convert.toStr(info.get("softwareVers")));
        response.setSerialNumber(Convert.toStr(cacheMap.get("wifiType")));
        response.setSupplier(equipmentDO.getSupplier());
        response.setMac(Convert.toStr(cacheMap.get("deviceId")));
        response.setCandidateModel(baseService.getCandidateModel(equipmentDO.getDeviceBaseId()));

        // 室外温度
        response.setOutdoorTemperature(Convert.toInt(reported.get("outdoorTemperature")));
        // 室内温度
        response.setTemperature(Convert.toInt(reported.get("indoorTemperature")));
        // 室内PM2.5
        response.setIndoorPM2p5(Convert.toInt(reported.get("indoorPM2p5Value")));
        // 室内湿度
        response.setIndoorHumidity(Convert.toInt(reported.get("indoorHumidity")));
        // 空气质量
        response.setAirQuality(airQuality.get(Convert.toInt(reported.get("airQuality"))));
        // 健康负离子模式开关
        response.setHealthMode(Convert.toBool(reported.get("healthMode")));
        // 蜂鸣器会响状态
        response.setEchoStatus(Convert.toBool(reported.get("echoStatus")));
        // 加湿功能
        response.setHumidificationStatus(Convert.toBool(reported.get("humidificationStatus")));
        // 温度显示
        response.setTempUnit(Convert.toInt(reported.get("tempUnit")));
        // 屏显功能
        response.setScreenDisplayStatus(Convert.toBool(reported.get("screenDisplayStatus")));
        // 上下摆风、左右摆风
        response.setWindDirectionVertical(Convert.toInt(reported.get("windDirectionVertical")));
        response.setWindDirectionHorizontal(Convert.toInt(reported.get("windDirectionHorizontal")));
        // 省电/ECO模式
        response.setEnergySavingStatus(Convert.toBool(reported.get("energySavingStatus")));
        // 功能模式 制冷、制热、送风、除湿、智能模式
        response.setMode(Convert.toInt(reported.get("operationMode")));
        // 新风功能开关
        response.setFreshAirStatus(Convert.toBool(reported.get("freshAirStatus")));
        // 风速
        response.setFanLevel(Convert.toInt(reported.get("windSpeed")));
        //电加热
        response.setElectricHeatingStatus(Convert.toBool(reported.get("electricHeatingStatus")));
        // 静音状态
        response.setMuteStatus(Convert.toBool(reported.get("muteStatus")));
        // 自清洁
        response.setSelfCleaningStatus(Convert.toBool(reported.get("selfCleaningStatus")));
        // 目标温度
        response.setTargetTemperature(Convert.toInt(reported.get("targetTemperature")));

        response.setModeList(modeList);
        response.setTemperatureRange(temperatureRange);
        response.setTargetTemperatureRange(targetTemperatureRange);
        response.setFanLevelList(fanLevelList);
        response.setHumidityRange(humidityRange);
        response.setTempUnitList(tempUnitList);
        response.setWindDirectionVerticalList(windDirectionVerticalList);
        response.setWindDirectionHorizontalList(windDirectionHorizontalList);


        final Map shadowInfo = (Map) cacheMap.get("shadowInfo");
        response.setOnline(Convert.toBool(shadowInfo.get("online"), false));
        equipmentMapper.updateEquipmentOnline(equipmentDO.getDeviceSn(), response.getOnline() ? 1L : 0L);

        return response;
    }

    /**
     * 控制设备
     *
     * @param equipmentDO 当前设备信息，包含设备id，设备厂商
     * @param type        控制类型，如温度、开关、模式
     * @param value       操作目标值  如 20°(20)、open(true)、冷风模式(3)
     * @return
     */
    @Override
    public Boolean control(EquipmentDO equipmentDO, String type, String value) {
        boolean flag;
        String thirdType; // 后面如果是组合命令，需要优化这个参数以便进行后续的操作
        // 下面看着像是一个属性一个控制，实际上一个属性只是对应一个控制的type名，也许某个type名对应着操作多个属性的指令（组合命令）
        // 如果是组合命令，需要优化以下逻辑判断
        final Long homeId = equipmentMapper.selectHomeIdByDeviceSn(equipmentDO.getDeviceSn());
        Map<String, Object> cacheMap = zhijiaService.getShadowByDeviceSn(homeId, equipmentDO.getDeptId(), equipmentDO.getDeviceSn());
        thirdType = isMutex(type, cacheMap);
        flag = zhijiaService.control(equipmentDO, thirdType, value);
        if (flag) {
            Map<String, String> properties = new HashMap<>();
            properties.put(thirdType, value);
            zhijiaService.resolveUhomeDeviceStatus(homeId, equipmentDO, properties, cacheMap);
            CompletableFuture.runAsync(() -> {
                // TODO 暂时去取数据，不从缓存中拿
//                Map<String, Object> cacheMap = zhijiaService.getShadowByDeviceSn(homeId, equipmentDO.getDeptId(), equipmentDO.getDeviceSn());
                List<Long> userIds = homeMapper.listUserIdsByDeptId(equipmentDO.getDeptId());
                Map<String, Object> data = new HashMap<>();
                data.put("deviceSn", equipmentDO.getDeviceSn());
                Map<String, Object> propertyMap = new HashMap<>();
                propertyMap.put(type, JSONObject.parseObject(cacheMap.get("reported").toString()).get(thirdType));
                data.put("properties", propertyMap);
                data.put("deviceType", equipmentDO.getDeviceType());

                Map<String, Object> pr = new HashMap<>();
                pr.put("code", HttpStatus.SUCCESS);
                pr.put("msg", "设备消息");
                pr.put("type", 3);
                pr.put("data", data);
                // 发送属性变化的推送
                userIds.forEach(userId -> WebsocketManager.appointSending(String.valueOf(userId), JSON.toJSONString(pr)));
            });
        }
        return flag;
    }

    private String isMutex(String type, Map<String, Object> cacheMap) {
        Map<String, String> reported = (Map<String, String>) cacheMap.get("reported");
        String thirdType;
//        String selfClean = reported.get("selfCleaningStatus");
//        if (!Objects.equals("selfCleaningStatus", type) && Convert.toBool(selfClean, false)) {
//            // 自清洁开启下，只有开关机可以操作
//            if (!Objects.equals(type, "onOffStatus")) {
//                throw new RuntimeException("自清洁模式下只能操作开关机");
//            }
//        }
        switch (type) {
            case "on":
                thirdType = "onOffStatus";
                break;
            case "targetTemperature":
                thirdType = "targetTemperature";
                // 送风模式下不能调节温度，Care模式下不能调节
                String operationMode = reported.get("operationMode");
                if (Objects.equals(operationMode, "6")) {
                    throw new RuntimeException("送风模式下无法调节温度");
                }
                break;
            case "healthMode":
                thirdType = "healthMode";
                break;
            case "echoStatus":
                thirdType = "echoStatus";
                break;
            case "humidificationStatus":
                thirdType = "humidificationStatus";
                break;
            case "tempUnit":
                thirdType = "tempUnit";
                break;
            case "screenDisplayStatus":
                thirdType = "screenDisplayStatus";
                break;
            case "windDirectionVertical":
                thirdType = "windDirectionVertical";
                break;
            case "windDirectionHorizontal":
                thirdType = "windDirectionHorizontal";
                break;
            case "energySavingStatus":
                thirdType = "energySavingStatus";
                break;
            case "mode":
                thirdType = "operationMode";
                break;
            case "freshAirStatus":
                thirdType = "freshAirStatus";
                break;
            case "fanLevel":
                thirdType = "windSpeed";
                // PMV模式和送风模式下与风速互斥
                String f = reported.get("operationMode");
                if (Objects.equals(f, "6") || Objects.equals(f, "0")) {
                    throw new RuntimeException("PMV模式、送风模式与风速互斥");
                }
                break;
            case "electricHeatingStatus":
                thirdType = "electricHeatingStatus";
                // 制冷、除湿、送风模式下与电加热互斥
                String es = reported.get("operationMode");
                if (Objects.equals(es, "1") || Objects.equals(es, "2") || Objects.equals(es, "6")) {
                    throw new RuntimeException("制冷、送风、除湿模式与电加热互斥");
                }
                break;
            case "muteStatus":
                thirdType = "muteStatus";
                // 除湿、送风、PMV模式与静音互斥
                String m = reported.get("operationMode");
                if (Objects.equals(m, "0") || Objects.equals(m, "2") || Objects.equals(m, "6")) {
                    throw new RuntimeException("除湿、送风、PMV模式与静音互斥");
                }
                break;
            case "selfCleaningStatus":
                thirdType = "selfCleaningStatus";
                String s = reported.get("operationMode");
                if (Objects.equals(s, "0")) {
                    throw new RuntimeException("PMV模式与自清洁互斥");
                }
                break;
            case "targetHumidity":
                thirdType = "targetHumidity";
                break;
            default:
                throw new RuntimeException("不支持的指令");
        }
        return thirdType;
    }


    // 空调模式预设值
    private List<Map<String, String>> modeList = new ArrayList<Map<String, String>>(5) {{
        add(createMap("智能/自动/舒适", "0"));
        add(createMap("制冷", "1"));
        add(createMap("除湿", "2"));
        add(createMap("制热", "4"));
        add(createMap("送风", "6"));
    }};

    // 温度单位切换
    private List<Map<String, String>> tempUnitList = new ArrayList<Map<String, String>>(2) {{
        add(createMap("摄氏度", "1"));
        add(createMap("华氏度", "2"));
    }};

    // 前后摆风
    private List<Map<String, String>> windDirectionVerticalList = new ArrayList<Map<String, String>>(2) {{
        add(createMap("固定", "0"));
        add(createMap("自动", "8"));
    }};
    // 左右摆风
    private List<Map<String, String>> windDirectionHorizontalList = new ArrayList<Map<String, String>>(2) {{
        add(createMap("固定", "0"));
        add(createMap("自动", "7"));
    }};

    private Map<Integer, String> airQuality = new HashMap<Integer, String>(4) {{
        put(0, "优");
        put(1, "良");
        put(2, "中");
        put(3, "差");
    }};

    //空调温度预设值
    private Map<String, String> temperatureRange = new HashMap<String, String>(4) {{
        put("min", "0");
        put("max", "55");
        put("step", "1");
    }};

    // 湿度 百分比
    private Map<String, String> humidityRange = new HashMap<String, String>(4) {{
        put("min", "0");
        put("max", "90");
        put("step", "1");
    }};

    //空调目标温度预设值
    private Map<String, String> targetTemperatureRange = new HashMap<String, String>(4) {{
        put("min", "16");
        put("max", "30");
        put("step", "1");
    }};

    //风力预设值
    private List<Map<String, String>> fanLevelList = new ArrayList<Map<String, String>>(4) {{
        add(createMap("高", "1"));
        add(createMap("中", "2"));
        add(createMap("低", "3"));
        add(createMap("自动", "5"));
    }};

    private Map<String, String> createMap(String key, String value) {
        Map<String, String> map = new HashMap<String, String>();
        map.put(key, value);
        return map;
    }
}
